#include <QtGui>
#include "video.h"

#define RADIUS 3
#define RADIUS2 6

DocWidget::DocWidget(QWidget *parent)
	:QWidget(parent)
{
  cap = NULL;
  m_pixmap = NULL;
  mouseMode = MouseNone;
  setMouseTracking(true);
  m_filterMode = 0;
  m_fac = 1.75;

  timer = new QTimer(this);
  connect(timer, SIGNAL(timeout()), this, SLOT(update()));
}

DocWidget::~DocWidget()
{
    if(cap) delete cap;
    if(timer) delete timer;
	if(m_pixmap) delete m_pixmap;
}

void DocWidget::update()
{
  if(cap){
    if(cap->read(m_oframe)){
      //cv::flip(m_oframe,m_oframe,1);
      cv::cvtColor(m_oframe,m_oframe,CV_BGR2RGB);
	  cv::resize(m_oframe, m_frame, Size(imageWidth,imageHeight));

	  filterImage();

	  if(roiRect.isValid()){
		  roix = roiRect.left()-dstx+srcx;
		  roiy = roiRect.top()-dsty+srcy;
		  roiw = roiRect.width();
		  roih = roiRect.height();
		  if(roix<0){
			  roiw += roix;
			  roix = 0;
		  }
		  if(roiy<0){
			  roih += roiy;
			  roiy = 0;
		  }
		  if((roiw >0) && (roih >0)){
			  Mat roi(m_image, Rect(roix,roiy,roiw,roih));
			  roiHist(roi);
		  }
	  }
    }
  }
}

void DocWidget::start()
{
    if(cap)delete cap;
    cap=new VideoCapture(0);
	//cap->set(CV_CAP_PROP_FRAME_WIDTH,1280);
	//cap->set(CV_CAP_PROP_FRAME_HEIGHT,720);
    cap->set(CV_CAP_PROP_FRAME_WIDTH,1920);
	cap->set(CV_CAP_PROP_FRAME_HEIGHT,1080);
    double fps = cap->get(CV_CAP_PROP_FPS);
    m_imageWidth = cap->get(CV_CAP_PROP_FRAME_WIDTH);
    m_imageHeight = cap->get(CV_CAP_PROP_FRAME_HEIGHT);
	//QMessageBox::information(this,"inform",QString("%1-%2").arg(m_imageWidth).arg(m_imageHeight));
	imageWidth = m_imageWidth * m_fac;
	imageHeight = m_imageHeight * m_fac;
	fitImage();

    if(fps<=0)fps=25;
    timer->start(1000/fps);
}

void DocWidget::stop()
{
    if(cap){
      delete cap;
      cap = NULL;
      timer->stop();
	  if(m_pixmap){
		  delete m_pixmap;
		  m_pixmap = NULL;
	  }
    }
}

void DocWidget::resizeEvent(QResizeEvent* event)
{
	fitImage();
}

void DocWidget::paintEvent(QPaintEvent* event)
{
	if(m_pixmap){
		QPainter painter(this);
		painter.setPen(QColor(255,0,0));
		painter.drawImage(dstx, dsty, *m_pixmap, srcx, srcy, srcw, srch);
		painter.drawRect(roiRect);
	}
}

void DocWidget::mousePressEvent(QMouseEvent *event)
{
	if(event->button() == Qt::LeftButton){
		int x=event->x(), y=event->y();
		if(QRect(roiRect.left()-RADIUS,roiRect.top()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			mouseMode = TopLeft;
		}else if(QRect(roiRect.right()-RADIUS,roiRect.top()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			mouseMode = TopRight;
		}else if(QRect(roiRect.left()-RADIUS,roiRect.bottom()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			mouseMode = BottomLeft;
		}else if(QRect(roiRect.right()-RADIUS,roiRect.bottom()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			mouseMode = BottomRight;
		}else {
			roiRect = QRect(x,y,0,0);
			mouseMode = BottomRight;
		}
	}else QWidget::mousePressEvent(event);
}

void DocWidget::mouseMoveEvent(QMouseEvent *event)
{
	int x=event->x(),y=event->y();
	switch(mouseMode){
		case TopLeft:
			if(x< roiRect.right())roiRect.setLeft(x);
			if(y< roiRect.bottom())roiRect.setTop(y);
			repaint();
			break;
		case TopRight:
			if(x> roiRect.left())roiRect.setRight(x);
			if(y<roiRect.bottom())roiRect.setTop(y);
			repaint();
			break;
		case BottomLeft:
			if(x< roiRect.right())roiRect.setLeft(x);
			if(y> roiRect.top())roiRect.setBottom(y);
			repaint();
			break;
		case BottomRight:
			if(x> roiRect.left())roiRect.setRight(x);
			if(y> roiRect.top())roiRect.setBottom(y);
			repaint();
			break;
		default:

		if(QRect(roiRect.left()-RADIUS,roiRect.top()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			setCursor(Qt::SizeFDiagCursor);
		}else if(QRect(roiRect.right()-RADIUS,roiRect.top()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			setCursor(Qt::SizeBDiagCursor);
		}else if(QRect(roiRect.left()-RADIUS,roiRect.bottom()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			setCursor(Qt::SizeBDiagCursor);
		}else if(QRect(roiRect.right()-RADIUS,roiRect.bottom()-RADIUS,RADIUS2,RADIUS2).contains(x,y)){
			setCursor(Qt::SizeFDiagCursor);
		}else setCursor(Qt::ArrowCursor);
			QWidget::mouseMoveEvent(event);
	}
}

void DocWidget::mouseReleaseEvent(QMouseEvent* event)
{
	if(event->button()==Qt::LeftButton){
		mouseMode = MouseNone;
		setCursor(Qt::ArrowCursor);
	}else
		QWidget::mouseReleaseEvent(event);
}

void DocWidget::fitImage()
{
	if(imageWidth<width()){
		dstx = (width()-imageWidth)/2;
		srcx = 0;
		srcw = imageWidth;
	}else{
		dstx = 0;
		srcx = (imageWidth-width())/2;
		srcw = width();
	}
	if(imageHeight<height()){
		dsty = (height()-imageHeight)/2;
		srcy = 0;
		srch = imageHeight;
	}else{
		dsty = 0;
		srcy = (imageHeight-height())/2;
		srch = height();
	}
}

void DocWidget::setFilter(int mode)
{
	m_filterMode = mode;
}

void DocWidget::setFactor(double fac)
{
	m_fac = fac;
	imageWidth = m_imageWidth * m_fac;
	imageHeight = m_imageHeight * m_fac;
	fitImage();
}

void DocWidget::snap()
{
if(cap){
	//cap->set(CV_CAP_PROP_FRAME_WIDTH,1920);
	//cap->set(CV_CAP_PROP_FRAME_HEIGHT,1080);

    if(cap->read(m_oframe)){
	QString fname = QString("snapshot/");
	fname += (QDateTime::currentDateTime()).toString("yy-MMdd-hh-mm-ss")+".png";
	//m_pixmap->save(fname);
	cv::imwrite(fname.toStdString(),m_oframe);
	}
	//cap->set(CV_CAP_PROP_FRAME_WIDTH,1280);
	//cap->set(CV_CAP_PROP_FRAME_HEIGHT,720);
	}
}

void DocWidget::filterImage()
{
	vector<Mat> vm;
	switch(m_filterMode) {
		case 0:
			m_image = m_frame;
			break;
		case 1:
			split(m_frame,vm);
			vm[1] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			vm[2] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			merge(vm,m_image);
			break;
		case 2:
			split(m_frame,vm);
			vm[0] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			vm[2] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			merge(vm,m_image);
			break;
		case 3:
			split(m_frame,vm);
			vm[0] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			vm[1] = Mat::zeros(m_frame.rows,m_frame.cols,CV_8UC1);
			merge(vm,m_image);
			break;
	}
	if(m_pixmap)delete(m_pixmap);
	m_pixmap = new QImage((const unsigned char *)(m_image.data),
	  	  m_image.cols,m_image.rows,QImage::Format_RGB888);
	repaint();
}

void DocWidget::roiHist(Mat image)
{
  int histSize[1];
  float hranges[2];
  const float* ranges[1];
  int channels[1],i;
  int oldy,y;

  histSize[0]=256;
  hranges[0]=0.0;
  hranges[1] = 255.0;
  ranges[0]=hranges;

  MatND hist;
  double mValue = image.rows * image.cols /5;
  int red[256],green[256],blue[256];
  channels[0]=0;
  calcHist(&image,1,channels,
	   Mat(),hist,1,histSize,ranges);
  for(i=0;i<256;i++)
    red[i] = 255-hist.at<float>(i)*255/mValue;

  channels[0]=1;
  calcHist(&image,1,channels,
	   Mat(),hist,1,histSize,ranges);
  for(i=0;i<256;i++)
    green[i] = 255-hist.at<float>(i)*255/mValue;

  channels[0]=2;
  calcHist(&image,1,channels,
	   Mat(),hist,1,histSize,ranges);
  for(i=0;i<256;i++)
    blue[i] = 255-hist.at<float>(i)*255/mValue;

  emit drawHist(red,green,blue);
}
